import {
  computed,
  defineComponent,
  nextTick,
  onMounted,
  ref,
  toRef,
  toRefs,
  useId,
  watch,
  watchPostEffect,
} from 'vue';
import type { CSSProperties, ExtractPublicPropTypes, PropType } from 'vue';
import { useTableColumnsStore } from '@/stores/modules/index';
import { useElementSize } from '@vueuse/core';
import { Card, ConfigProvider, Pagination, Table } from 'ant-design-vue';
import type {
  TableColumnProps,
  TableColumnType,
  TablePaginationConfig,
  TableProps,
} from 'ant-design-vue';
import { Key } from 'ant-design-vue/es/_util/type';
import { tableProps } from 'ant-design-vue/es/table';
import { usePagination } from 'vue-request';
import SearchForm from './components/Search/Index.vue';
import { Options } from './components/options/Index';
import { useColumnsStore, useProvideColumnsStore } from './store/index';
import { getWidth, handleCustomRender } from './utils';

const proTableProps = () => ({
  ...tableProps(),
  align: {
    type: String as PropType<TableColumnProps['align']>,
    default: 'center',
  },
  // 模拟数据
  mockData: {
    type: Object as PropType<any>,
    default: () => ({}),
  },
  fetchListApi: {
    type: Function as PropType<(params: any) => Promise<any>>,
    default: (data: any) => data,
  },
  autoLoad: {
    type: Boolean,
    default: true,
  },
  formatResponse: {
    type: Function as PropType<(res: any) => { rows: any[]; total: number }>,
    default: (data: any) => data,
  },
  height: {
    type: Number,
    default: 0,
  },
  hideTableOptions: {
    type: Boolean,
    default: false,
  },
  hideSearch: {
    type: Boolean,
    default: false,
  },
  hidePagination: {
    type: Boolean,
    default: false,
  },
  remoteColumns: {
    type: Function as PropType<() => Promise<TableColumnType[]>>,
    default: async function () {
      const store = useTableColumnsStore();
      return store?.currentColumns;
    },
  },
  setRemoteColumns: {
    type: Function as PropType<(columns: TableColumnType[]) => void>,
    default: async function (columns: TableColumnType[]) {
      const store = useTableColumnsStore();
      return store?.updateColumns(columns);
    },
  },
  onValuesChange: {
    type: Function as PropType<
      (params: Record<string, any>, formState: Record<string, any>) => void
    >,
    default: () => {},
  },
  hideLoading: {
    type: Boolean,
    default: false,
  },
  formCol: {
    type: Object,
    default: () => {
      return { md: 24, lg: 14, xl: 18, xxl: 21 };
    },
  },
  btnCol: {
    type: Object,
    default: () => {
      return { md: 24, lg: 10, xl: 6, xxl: 3 };
    },
  },
  searchText: {
    type: String,
    default: '搜索',
  },
  onFromReset: {
    type: Function as PropType<(formState: Record<string, any>) => void>,
    default: () => {},
  },
  searchClassName: {
    type: String,
    default: '',
  },
});

const props = proTableProps();

type ProTableProps = ExtractPublicPropTypes<typeof props>;

const ProTable = defineComponent({
  name: 'ProTable',
  props: props,
  setup(props, { slots, expose }) {
    const {
      fetchListApi,
      autoLoad,
      formatResponse,
      height,
      hideSearch,
      rowSelection,
      mockData,
      dataSource,
      hidePagination,
      hideTableOptions,
      onValuesChange,
      onFromReset,
      ...tableProps
    } = props;

    const {
      leftContent,
      toolbars,
      control,
      bodyCell,
      rightContent,
      customTable,
      footer,
      ...otherSlots
    } = slots;

    const searchParams = ref({});
    const service = async (params: any) => {
      const res = await fetchListApi!({ ...params, ...searchParams.value });
      console.debug('pro-table fetch list result: ', res);
      if (mockData?.rows?.length > 0) {
        return formatResponse(mockData);
      }
      return formatResponse(res);
    };
    const { data, current, pageSize, loading, total, changePagination } =
      usePagination(service, {
        manual: true,
        defaultParams: [
          {
            pageSize: 15,
          },
        ],
        pagination: {
          totalKey: 'total',
          currentKey: 'pageNum',
          pageSizeKey: 'pageSize',
        },
      });
    const list = computed(() => {
      return data.value?.rows || [];
    });
    const formRef = ref();
    onMounted(() => {
      if (autoLoad !== false) {
        nextTick(() => {
          hideSearch
            ? changePagination(current.value, 15)
            : formRef.value?.search();
        });
      }
    });
    const pagination = computed<TablePaginationConfig>(() => {
      return {
        total: total.value,
        current: current.value,
        pageSize: pageSize.value,
        pageSizeOptions: ['15', '30', '45'],
        onChange: changePagination,
        showTotal: (total) => `共${total}条`,
        showSizeChanger: true,
        showQuickJumper: true,
      };
    });

    const onSearch = (params: Record<string, any>) => {
      searchParams.value = params;
      changePagination(_isFirstPage ? 1 : current.value, pageSize.value);
      _isFirstPage = true;
    };
    let _isFirstPage = true;
    const search = (
      params?: Record<string, any>,
      isFirstPage: boolean = true,
    ) => {
      _isFirstPage = isFirstPage;
      formRef.value.search(params);
    };
    const refresh = (isFirstPage: boolean = true) => {
      hideSearch
        ? isFirstPage
          ? changePagination(1, 15)
          : changePagination(current.value, 15)
        : formRef.value.reset();
    };

    expose({
      refresh,
      search,
    });

    const currentId = useId();
    // 判断当前是否在 Modal 内部，如果在，则当前 table columns
    const isInModal = ref(false);
    onMounted(() => {
      const node = document.getElementById(currentId!);
      if (node!.closest('.ant-modal') !== null) {
        isInModal.value = true;
      }
    });

    useProvideColumnsStore({
      remoteColumns: props.remoteColumns,
      setRemoteColumns: props.setRemoteColumns,
    });
    const { currentColumns, updateSourceColumns } = useColumnsStore()!;
    watch(
      () => props.columns,
      (val) => {
        updateSourceColumns(val.filter((item) => item.hideInTable !== true));
      },
      { deep: true, immediate: true },
    );
    const columns = ref([]);
    watchPostEffect(() => {
      const result = (
        isInModal.value
          ? props.columns.filter((item) => item.hideInTable !== true)
          : currentColumns.value
      )
        .reduce<TableColumnType[][]>(
          (prev, item) => {
            if (item.checked === false) return prev;
            if (item.valueEnum && !item.customRender) {
              item.customRender = ({ text }) => {
                const value = item.valueEnum![text];
                const width = Math.max(
                  ...Array.from(
                    new Set(list.value.map((data) => data[item.dataIndex!])),
                    (t) => getWidth(item.valueEnum[t] as string),
                  ),
                  getWidth(item.title as string),
                );
                item.__width = width;
                return value;
              };
            } else if (item.customRender) {
              item.customRender = handleCustomRender(item.customRender, {
                pageNum: current,
                pageSize: pageSize,
              });
            } else {
              item.__width = Math.max(
                ...list.value.map((data) => {
                  const result = getWidth(data[item.dataIndex] as string);
                  return result;
                }),
                getWidth(item.title as string),
              );
            }
            (Number.isNaN(item.__width) || !item.__width) &&
              (item.__width = 240);
            item.align = item.align || props.align;
            if (item.fixed === 'right') {
              prev[2].push(item);
            } else if (item.fixed) {
              prev[0].push(item);
            } else {
              prev[1].push(item);
            }
            return [...prev];
          },
          [[], [], []],
        )
        .flat();
      columns.value = result as any;
    });
    const onFormChange = (params: any, formState: any) => {
      onValuesChange(params, formState);
    };
    const onReset = (params: any) => {
      onFromReset(params);
    };
    const flexRef = ref();
    const toolbarsRef = ref();
    const paginationRef = ref();
    const { height: containerHeight } = useElementSize(flexRef);
    const { height: toolbarHeight } = useElementSize(toolbarsRef);
    const { height: searchFormHeight } = useElementSize(formRef);
    const { height: paginationHeight } = useElementSize(paginationRef);

    const styleProps = computed<{
      scroll: TableProps['scroll'];
      style: CSSProperties;
    }>(() => {
      let y =
        (height || containerHeight.value) -
        toolbarHeight.value -
        searchFormHeight.value -
        paginationHeight.value -
        46;
      // TODO 减去表头高度，此处待优化，目前不确定是不是动态值

      if (toolbarsRef.value) {
        const p1 = window.getComputedStyle(toolbarsRef.value).paddingBottom;
        const p2 = window.getComputedStyle(paginationRef.value).paddingTop;
        const p3 = window.getComputedStyle(paginationRef.value).paddingBottom;

        y = [p1, p2, p3].reduce((prev, cur) => {
          prev -= Number(cur.replace('px', ''));
          return prev;
        }, y);
      }

      return {
        scroll: {
          x: 500,
          y,
        },
        style: {
          ['--pro-table-body-height']: `${y}px`,
        },
      };
    });
    const _bodyCell = (scope: { column: { dataIndex: string | number } }) => {
      return slots[scope.column.dataIndex]?.(scope);
    };
    return () => (
      <ConfigProvider
        theme={{
          components: {
            Card: {
              colorBorderSecondary: 'transparent',
              colorBgContainer: 'transparent',
            },
          },
        }}
      >
        <Card
          // @ts-ignore
          id={currentId}
          class='h-full'
          bodyStyle={{
            height: '100%',
            overflow: 'hidden',
            padding: '18px 0 0',
          }}
        >
          <div class='w-full h-full flex'>
            <div class='pro-table-control'>
              {control?.({
                search,
                searchParams: searchParams.value,
              })}
            </div>
            <div
              ref={flexRef}
              id='pro-table-container'
              class='flex-1 overflow-x-hidden flex flex-col h-full'
            >
              {!hideSearch && (
                <SearchForm
                  ref={formRef}
                  class={'pro-search-form-wrap ' + props.searchClassName}
                  items={props.columns}
                  formCol={props.formCol}
                  btnCol={props.btnCol}
                  searchText={props.searchText}
                  onSearch={(params) => onSearch(params)}
                  onChange={(params, formState) =>
                    onFormChange(params, formState)
                  }
                  onReset={(params) => onReset(params)}
                />
              )}
              <div
                ref={toolbarsRef}
                class='toolbar-wrap pb-2 px-4 flex flex-row-reverse justify-between items-center'
              >
                {!isInModal.value && !hideTableOptions && <Options />}
                <ConfigProvider
                  theme={{ components: { Button: { controlHeight: 26 } } }}
                >
                  {toolbars?.()}
                </ConfigProvider>
              </div>

              {customTable?.({
                data: list.value,
                loading: loading.value,
                columns: columns.value,
              }) || (
                <div class='flex-1 overflow-hidden flex items-start'>
                  {leftContent?.({ data: list.value })}
                  <Table
                    class='pro-table  flex-1'
                    {...props}
                    {...styleProps.value}
                    dataSource={list.value}
                    columns={columns.value.map((item) => {
                      const width = item.width ?? item.__width + 18;
                      return {
                        ...item,
                        width,
                      };
                    })}
                    pagination={false}
                    loading={props.hideLoading ? false : loading.value}
                  >
                    {{
                      ...otherSlots,
                      bodyCell: bodyCell ?? _bodyCell,
                    }}
                  </Table>

                  {rightContent?.({ data: list.value })}
                </div>
              )}
              <div
                ref={paginationRef}
                class='flex justify-between py-2 pro-pagination'
              >
                <div>{footer?.()}</div>
                {!hidePagination && <Pagination {...pagination.value} />}
              </div>
            </div>
          </div>
        </Card>
      </ConfigProvider>
    );
  },
});

export { ProTable, type ProTableProps };
